Especialista en Métodos Cuantitativos para la Gestión y Análisis de Datos en Organizaciones (FCE, UBA). Lic. en Economía (FCE, UNLP). Líder técnica de Ciencia de Datos (Ualá).
Organizadora: Natalia R. Salaberry Doctora en la Universidad de Buenos Aires, Ciencias Económicas. Magister en Métodos Cuantitativos para la Gestión y Análisis de Datos en Organizaciones (FCE, UBA). Lic. en Economía, FCE, UBA. Investigadora en CIMBAGE (IADCOM), Docente de posgrados y Estadística I, FCE, UBA
Se cuenta con un dataset de 1852394 transacciones de tarjetas de crédito. Son 13 variables generadas sintéticamente por lo que el foco está sobre cómo procesarlos y no sobre la performance del modelo.
No se cuenta con valores faltantes, por lo que se genera “ruido” en el dataset, añadiendo valores faltantes en distintas variables para el ejemplo.
La Figura Figura 2 muestra un posible esquema de trabajo para modelos de aprendizaje automático en donde se busca predecir sobre datos nuevos.
Figura 2: Esquema de modelado
2.2 Particiones
Partición en dataset de entrenamiento y evaluación.
Dataset de entrenamiento –> Ajuste del modelo
Dataset de evaluación –> Métricas
Generación de particiones
y = df[target]X = df.drop([target], axis=1)X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, shuffle=True, stratify=y, random_state=42)display(Markdown(f"N observaciones en entrenamiento: {X_train.shape[0]}"))display(Markdown(f"N observaciones en evaluación: {X_test.shape[0]}"))
N observaciones en entrenamiento: 1296675
N observaciones en evaluación: 555719
3 Preprocesamiento
3.1 Tipos de transformaciones
Ciertos tipos de transformaciones requieren “aprender” algunos aspectos de los datos mientras que otras no.
Ejemplos de transformaciones que dependen de los datos de entrenamiento:
Imputación de valores faltantes con la mediana → La mediana depende de los datos
Escalado → Se debe calcular la media y desvío estándar de los datos
Ejemplos de transformaciones que no dependen de los datos de entrenamiento:
Construcción de una nueva variable mediante un cálculo simple → x^2
Combinaciones de variables en una nueva variable → x/y
3.2 Transformaciones en python, mediante scikit-learn
Para implementar este tipo de aprendizajes de ciertos aspectos de los datos al generar transformaciones custom, en scikit-learn se utiliza una clase específica TransformerMixin.
Figura 3: Diagrama transformers
3.3 Transformaciones iniciales
Cálculo de la edad
Cálculo de la distancia entre el comercio y el usuario
Generación de variables vinculadas a la fecha y hora de la transacción
Transformaciones iniciales
class TransformacionesIniciales(BaseEstimator, TransformerMixin):""" Transformaciones iniciales del dataset. """def__init__(self, age_features=True, timestamp_features=True, distance_features=True):""" Args: timestamp_features (bool): Generar variables basadas en la fecha/hora de la trx distance_features (bool): Generar variables basadas en la distancia al comercio """self.age_features = age_featuresself.timestamp_features = distance_featuresself.distance_features = distance_featuresdef fit(self, X, y=None):returnselfdef transform(self, X, y=None):# Se genera una copia para no afectar al df original: X_ = X.copy()# Cast features: X_ = (X_ .assign( dob =lambda x: pd.to_datetime(x['dob'], errors='coerce'), trans_date_trans_time =lambda x: pd.to_datetime(x["trans_date_trans_time"], errors="coerce"), ) )# Features basadas en la edad:ifself.age_features: X_ = X_.assign( age =lambda x: round((x['trans_date_trans_time']-x['dob']).dt.days /365.25,2) )# Features basadas en fecha y hora de la trx:def categorize_part_of_day(hour):if5<= hour <12:return'Morning'elif12<= hour <17:return'Afternoon'elif17<= hour <21:return'Evening'elif21<= hour or hour <5:return'Night'ifself.timestamp_features: X_ = X_.assign( trans_date__year =lambda x: x["trans_date_trans_time"].dt.year, trans_date__month =lambda x: x["trans_date_trans_time"].dt.month, trans_date__day =lambda x: x["trans_date_trans_time"].dt.day, trans_date__dow =lambda x: x["trans_date_trans_time"].dt.dayofweek, trans_date__hour =lambda x: x["trans_date_trans_time"].dt.hour, trans_date__partofday =lambda x: x['trans_date__hour'].apply(categorize_part_of_day) )ifself.distance_features:# Latitud y longitud en radianes lat1 = np.radians(X_['lat']) lon1 = np.radians(X_['long']) lat2 = np.radians(X_['merch_lat']) lon2 = np.radians(X_['merch_long'])# Fórmula Haversine para calcular la distancia: dlat = lat2 - lat1 dlon = lon2 - lon1 a = np.sin(dlat /2) **2+ np.cos(lat1) * np.cos(lat2) * np.sin(dlon /2) **2 c =2* np.arctan2(np.sqrt(a), np.sqrt(1- a)) R =6371# Radio de la tierra (en kilometros) X_['distance_to_merch'] =round(R * c, 3) # Distancia (en kilometros) X_ = X_.drop(['trans_date_trans_time','dob'], axis=1) return X_